// D_WIDTH  : data width
// PA_WIDTH : port (i.e. IO channel) address width
 
module core#(parameter D_WIDTH = 34, IA_WIDTH = 10, I_WIDTH = 17, PA_WIDTH = 4)
(
    input  clk,
    input  reset_i,
    
    // I/O interface
    input  [D_WIDTH-1 : 0]  in_data_i,
    input  in_ack_i,
    input  out_ack_i,
    output in_req_o,
    output out_req_o,
    output [PA_WIDTH-1 : 0] in_addr_o,
    output [PA_WIDTH-1 : 0] out_addr_o,
    output [D_WIDTH-1 : 0]  out_data_o
);

////////////////////////////////////////////////////////////////////////
// backend registers
    
    // outputs to the fetch unit
    wire back_dequeue;
    wire back_restart;
    wire [IA_WIDTH-1 : 0] back_restart_addr;
    wire back_branch;
    
    // outputs to the fetch unit (NOT USED)
    wire back_load_store_valid;
    wire back_store_en;
    wire [IA_WIDTH-1 : 0] back_load_store_addr;
    wire [I_WIDTH-1 : 0]  back_store_data;
    
////////////////////////////////////////////////////////////////////////
// frontend registers (fetch)

	wire [I_WIDTH-1 : 0] front_instruction_data;
	wire [IA_WIDTH-1 : 0] front_instruction_addr;
	wire front_instruction_valid;
	wire [I_WIDTH-1:0] front_load_data;
	wire front_load_data_valid;
	
	reg delay1_r;
	reg delay2_r;
	
	always_ff @(posedge clk)
	begin
		delay1_r <= reset_i;
		delay2_r <= delay1_r;
	end
////////////////////////////////////////////////////////////////////////
// fetch module

	fetch front_end (
		 .clk(clk)

		 // inputs from exec unit
		 ,.dequeue_i(back_dequeue)
		 ,.restart_i(reset_i)
		 ,.restart_addr_i(back_restart_addr)
		 ,.branch_i(back_branch)
		 
		 // memory interface (NOT USED)
		 ,.load_store_valid_i(back_load_store_valid)
		 ,.store_en_i(back_store_en)
		 ,.load_store_addr_i(back_load_store_addr)
		 ,.store_data_i(back_store_data)
		 ,.load_data_o(front_load_data)
		 ,.load_data_valid_o(front_load_data_valid)
		 
		 // ouputs to the exec unit
		 ,.instruction_data_o(front_instruction_data)
		 ,.instruction_addr_o(front_instruction_addr)
		 ,.instruction_valid_o(front_instruction_valid)
		);
		
////////////////////////////////////////////////////////////////////////
// backend module

    backend back_end (
    
       .clk(clk),
	    .reset_i(delay2_r),
	    
	    // inputs from the fetch unit
	    .instruction_data_i(front_instruction_data),
	    .instruction_addr_i(front_instruction_addr),
	    .instruction_valid_i(front_instruction_valid),    
	    .load_data_i(front_load_data),
	    .load_data_valid_i(front_load_data_valid),
	    
	    // outputs to the fetch unit
	    .dequeue_o(back_dequeue),
	    .restart_o(back_restart),
	    .restart_addr_o(back_restart_addr),
	    .branch_o(back_branch),
	    
	    .load_store_valid_o(back_load_store_valid),
	    .store_en_o(back_store_en),
	    .load_store_addr_o(back_load_store_addr),
	    .store_data_o(back_store_data),
	    
	    // I/O interface
	    .in_req_o(in_req_o),
	    .out_req_o(out_req_o),
	    .in_addr_o(in_addr_o),
	    .out_addr_o(out_addr_o),
	    .in_data_i(in_data_i),
	    .out_data_o(out_data_o),
	    .in_ack_i(in_ack_i),
	    .out_ack_i(out_ack_i)
    );

////////////////////////////////////////////////////////////////////////
		
endmodule